package com.cn.stepLock.chain;

import com.cn.stepLock.enums.ChainType;
import org.omg.CORBA.PUBLIC_MEMBER;

import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;

import static com.cn.stepLock.chain.ChainUtils.*;
import static com.cn.stepLock.chain.ChainUtils.startProcessChain;

/**
 * @author Aaron
 * @desc
 * @createTime 2022-02-24 4:15
 * @since
 */
public class ChainHelper {

    ChainManager chainManager;

    private int chainCount;

    public ChainHelper initExecuteChain(List<Task> taskList){
        ProcessChain firstProcessChain = new SynchronizedProcessChain();
        firstProcessChain.setIndex(1);
        ProcessChain preProcessChain = firstProcessChain;
        for (int i = 0; i < taskList.size()-1; i++) {
            ProcessChain nextChain = new ParkProcessChain();
            nextChain.setIndex(i+2);
            addChain(preProcessChain,nextChain);
            preProcessChain = nextChain;
        }
        insertChainIntoTask(taskList.get(0),firstProcessChain);
        startProcessChain(firstProcessChain);
        ConstentChain head = new HeadChain(this);
        head.start();
        chainManager = new ChainManager(head,firstProcessChain,new TailChain(),new ExceptionChain());
        ChainEventApplication.initListenerList(this);
        return this;
    }

    public void stop(){
        chainManager.head.stop();
        stopProcessChain(chainManager.firstProcess);
    }

    public int getProcessChainCount(){
        if (chainCount>0){
            return chainCount;
        }
        ProcessChain chain = this.chainManager.firstProcess;
        int count = 0;
        while (chain!=null){
            count++;
            chain = chain.nextChain;
        }
        chainCount = count;
        return chainCount;
    }

    public void executeHead(Task task){
        chainManager.head.executeTask(task);
    }

    public void executeTail(Task task){
        chainManager.tail.executeTask(task);
    }

    public void executeException(Task task){
        chainManager.exception.executeTask(task);
    }

    public void executeFirstProcess(Task task){
        chainManager.firstProcess.executeTask(task);
    }

    public void executeSynchronizedChain(Task task,SynchronizedProcessChain processChain){
        processChain.executeTask(task);
    }

    public void executeParkChain(Task task,ParkProcessChain processChain){
        processChain.executeTask(task);
    }

    void setChainExceptTaskCount(int exceptTaskCount){
        int currentExceptTaskCount = exceptTaskCount;
        ProcessChain processChain = chainManager.firstProcess;
        while (processChain!=null){
            processChain.exceptCount = new AtomicInteger(currentExceptTaskCount);
            if (processChain.chainType == ChainType.PARK.getValue()){
                processChain.taskLinkedBlockingQueue.exceptTaskCount = processChain.exceptCount;
            }
            processChain = processChain.nextChain;
        }
    }
}
